// JavaScript数组频次统计方法大全

console.log("=== JavaScript数组频次统计方法大全 ===\n");

// 测试数据
const numberArray = [1, 1, 1, 2, 2, 3, 3, 4, 5];
const stringArray = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple'];
const mixedArray = [1, '1', 1, 'a', 'a', 2, '2', 2];
const complexArray = [
    {id: 1, name: 'Alice'}, 
    {id: 1, name: 'Alice'}, 
    {id: 2, name: 'Bob'}, 
    {id: 1, name: 'Alice'}
];

console.log("数字数组:", numberArray);
console.log("字符串数组:", stringArray);
console.log("混合类型数组:", mixedArray);
console.log("对象数组:", complexArray);
console.log("\n" + "=".repeat(60) + "\n");

// ===== 方法1: for循环 =====
console.log("=== 方法1: 传统for循环 ===");
function countByForLoop(arr) {
    const result = {};
    for (let i = 0; i < arr.length; i++) {
        const item = arr[i];
        if (result[item]) {
            result[item]++;
        } else {
            result[item] = 1;
        }
    }
    return result;
}
console.log("for循环结果:", countByForLoop(numberArray));

// ===== 方法2: forEach循环 =====
console.log("\n=== 方法2: forEach循环 ===");
function countByForEach(arr) {
    const result = {};
    arr.forEach(item => {
        result[item] = (result[item] || 0) + 1;
    });
    return result;
}
console.log("forEach结果:", countByForEach(numberArray));

// ===== 方法3: reduce方法 =====
console.log("\n=== 方法3: reduce方法 ===");
function countByReduce(arr) {
    return arr.reduce((acc, item) => {
        acc[item] = (acc[item] || 0) + 1;
        return acc;
    }, {});
}
console.log("reduce结果:", countByReduce(numberArray));

// ===== 方法4: Map数据结构 =====
console.log("\n=== 方法4: Map数据结构 ===");
function countByMap(arr) {
    const map = new Map();
    arr.forEach(item => {
        map.set(item, (map.get(item) || 0) + 1);
    });
    return Object.fromEntries(map);
}
console.log("Map结果:", countByMap(numberArray));

// ===== 方法5: filter方法 =====
console.log("\n=== 方法5: filter方法 ===");
function countByFilter(arr) {
    const uniqueItems = [...new Set(arr)];
    const result = {};
    uniqueItems.forEach(item => {
        result[item] = arr.filter(x => x === item).length;
    });
    return result;
}
console.log("filter结果:", countByFilter(numberArray));

// ===== 方法6: while循环 =====
console.log("\n=== 方法6: while循环 ===");
function countByWhile(arr) {
    const result = {};
    let i = 0;
    while (i < arr.length) {
        const item = arr[i];
        result[item] = (result[item] || 0) + 1;
        i++;
    }
    return result;
}
console.log("while循环结果:", countByWhile(numberArray));

// ===== 方法7: 对象属性检查方法 =====
console.log("\n=== 方法7: 对象属性检查方法 ===");
function countByProperty(arr) {
    const result = {};
    arr.forEach(item => {
        if (result.hasOwnProperty(item)) {
            result[item]++;
        } else {
            result[item] = 1;
        }
    });
    return result;
}
console.log("属性检查结果:", countByProperty(numberArray));

// ===== 方法8: 递归方法 =====
console.log("\n=== 方法8: 递归方法 ===");
function countByRecursion(arr, index = 0, result = {}) {
    if (index >= arr.length) return result;
    
    const item = arr[index];
    result[item] = (result[item] || 0) + 1;
    
    return countByRecursion(arr, index + 1, result);
}
console.log("递归结果:", countByRecursion(numberArray));

// ===== 方法9: 函数式编程 =====
console.log("\n=== 方法9: 函数式编程风格 ===");
const countFunctional = arr => 
    arr.reduce((acc, item) => ({...acc, [item]: (acc[item] || 0) + 1}), {});
console.log("函数式结果:", countFunctional(numberArray));

// ===== 方法10: 分组后统计 =====
console.log("\n=== 方法10: 分组后统计 ===");
function countByGrouping(arr) {
    const grouped = arr.reduce((acc, item) => {
        if (!acc[item]) acc[item] = [];
        acc[item].push(item);
        return acc;
    }, {});
    
    const result = {};
    for (const key in grouped) {
        result[key] = grouped[key].length;
    }
    return result;
}
console.log("分组统计结果:", countByGrouping(numberArray));

// ===== 方法11: sort排序后统计 =====
console.log("\n=== 方法11: 排序后统计 ===");
function countBySort(arr) {
    const sorted = [...arr].sort();
    const result = {};
    let current = sorted[0];
    let count = 1;
    
    for (let i = 1; i < sorted.length; i++) {
        if (sorted[i] === current) {
            count++;
        } else {
            result[current] = count;
            current = sorted[i];
            count = 1;
        }
    }
    
    if (sorted.length > 0) {
        result[current] = count;
    }
    
    return result;
}
console.log("排序统计结果:", countBySort(numberArray));

// ===== 方法12: Set配合filter =====
console.log("\n=== 方法12: Set配合filter ===");
function countBySetFilter(arr) {
    const uniqueValues = [...new Set(arr)];
    return uniqueValues.reduce((acc, value) => {
        acc[value] = arr.filter(item => item === value).length;
        return acc;
    }, {});
}
console.log("Set+filter结果:", countBySetFilter(numberArray));

// ===== 方法13: indexOf配合lastIndexOf =====
console.log("\n=== 方法13: indexOf配合lastIndexOf ===");
function countByIndexOf(arr) {
    const result = {};
    const processed = new Set();
    
    arr.forEach((item, index) => {
        if (!processed.has(item)) {
            let count = 0;
            let searchIndex = 0;
            
            while ((searchIndex = arr.indexOf(item, searchIndex)) !== -1) {
                count++;
                searchIndex++;
            }
            
            result[item] = count;
            processed.add(item);
        }
    });
    
    return result;
}
console.log("indexOf结果:", countByIndexOf(numberArray));

// ===== 方法14: 双重循环 =====
console.log("\n=== 方法14: 双重循环 ===");
function countByDoubleLoop(arr) {
    const result = {};
    const processed = [];
    
    for (let i = 0; i < arr.length; i++) {
        if (processed.includes(arr[i])) continue;
        
        let count = 0;
        for (let j = 0; j < arr.length; j++) {
            if (arr[i] === arr[j]) {
                count++;
            }
        }
        
        result[arr[i]] = count;
        processed.push(arr[i]);
    }
    
    return result;
}
console.log("双重循环结果:", countByDoubleLoop(numberArray));

// ===== 方法15: 生成器函数 =====
console.log("\n=== 方法15: 生成器函数 ===");
function* countGenerator(arr) {
    const counts = {};
    for (const item of arr) {
        counts[item] = (counts[item] || 0) + 1;
        yield [item, counts[item]];
    }
}

function countByGenerator(arr) {
    const result = {};
    for (const [item, count] of countGenerator(arr)) {
        result[item] = count;
    }
    return result;
}
console.log("生成器结果:", countByGenerator(numberArray));

// ===== 方法16: 类封装方法 =====
console.log("\n=== 方法16: 类封装方法 ===");
class FrequencyCounter {
    static count(arr) {
        const counter = new this();
        return counter.countItems(arr);
    }
    
    countItems(arr) {
        const result = {};
        arr.forEach(item => {
            this.increment(result, item);
        });
        return result;
    }
    
    increment(obj, key) {
        obj[key] = (obj[key] || 0) + 1;
    }
}
console.log("类方法结果:", FrequencyCounter.count(numberArray));

// ===== 针对特殊情况的方法 =====
console.log("\n=== 特殊情况处理 ===");

// 方法17: 处理字符串数组
console.log("\n=== 方法17: 字符串数组处理 ===");
function countStrings(arr) {
    return arr.reduce((acc, str) => {
        const key = String(str); // 确保是字符串
        acc[key] = (acc[key] || 0) + 1;
        return acc;
    }, {});
}
console.log("字符串数组:", stringArray);
console.log("字符串统计:", countStrings(stringArray));

// 方法18: 处理混合类型
console.log("\n=== 方法18: 混合类型处理 ===");
function countMixedTypes(arr) {
    return arr.reduce((acc, item) => {
        const key = typeof item + ':' + String(item);
        acc[key] = (acc[key] || 0) + 1;
        return acc;
    }, {});
}
console.log("混合数组:", mixedArray);
console.log("混合类型统计:", countMixedTypes(mixedArray));

// 方法19: 处理对象数组
console.log("\n=== 方法19: 对象数组处理 ===");
function countObjects(arr, keyFunc) {
    return arr.reduce((acc, obj) => {
        const key = keyFunc ? keyFunc(obj) : JSON.stringify(obj);
        acc[key] = (acc[key] || 0) + 1;
        return acc;
    }, {});
}
console.log("对象数组:", complexArray);
console.log("按JSON统计:", countObjects(complexArray));
console.log("按id统计:", countObjects(complexArray, obj => obj.id));
console.log("按name统计:", countObjects(complexArray, obj => obj.name));

// 方法20: WeakMap方法（适用于对象）
console.log("\n=== 方法20: WeakMap方法 ===");
function countByWeakMap(arr) {
    // 注意: WeakMap只能用于对象，这里演示概念
    const result = {};
    const map = new Map(); // 实际使用Map演示
    
    arr.forEach(item => {
        map.set(item, (map.get(item) || 0) + 1);
    });
    
    map.forEach((count, key) => {
        result[key] = count;
    });
    
    return result;
}
console.log("WeakMap概念结果:", countByWeakMap(numberArray));

// ===== 性能测试 =====
console.log("\n=== 性能测试 ===");

// 创建大数组进行性能测试
const largeArray = Array.from({length: 10000}, () => Math.floor(Math.random() * 100));
console.log("测试数组长度:", largeArray.length);

function performanceTest(func, name, arr) {
    const start = performance.now();
    const result = func(arr);
    const end = performance.now();
    const uniqueKeys = Object.keys(result).length;
    console.log(`${name}: ${(end - start).toFixed(2)}ms, 统计了${uniqueKeys}个不同值`);
}

console.log("\n主要方法性能对比:");
performanceTest(countByForLoop, "for循环", largeArray);
performanceTest(countByForEach, "forEach", largeArray);
performanceTest(countByReduce, "reduce", largeArray);
performanceTest(countByMap, "Map方法", largeArray);
performanceTest(countByFilter, "filter方法", largeArray);

// ===== 工具函数 =====
console.log("\n=== 实用工具函数 ===");

// 获取出现次数最多的元素
function getMostFrequent(arr) {
    const counts = countByReduce(arr);
    let maxCount = 0;
    let mostFrequent = null;
    
    for (const [item, count] of Object.entries(counts)) {
        if (count > maxCount) {
            maxCount = count;
            mostFrequent = item;
        }
    }
    
    return {item: mostFrequent, count: maxCount};
}

// 获取出现次数最少的元素
function getLeastFrequent(arr) {
    const counts = countByReduce(arr);
    let minCount = Infinity;
    let leastFrequent = null;
    
    for (const [item, count] of Object.entries(counts)) {
        if (count < minCount) {
            minCount = count;
            leastFrequent = item;
        }
    }
    
    return {item: leastFrequent, count: minCount};
}

// 按频次排序
function sortByFrequency(arr, ascending = false) {
    const counts = countByReduce(arr);
    return Object.entries(counts)
        .sort((a, b) => ascending ? a[1] - b[1] : b[1] - a[1])
        .map(([item, count]) => ({item, count}));
}

console.log("原数组:", numberArray);
console.log("出现最多:", getMostFrequent(numberArray));
console.log("出现最少:", getLeastFrequent(numberArray));
console.log("按频次降序:", sortByFrequency(numberArray));
console.log("按频次升序:", sortByFrequency(numberArray, true));

// 过滤指定频次的元素
function filterByFrequency(arr, targetCount) {
    const counts = countByReduce(arr);
    return arr.filter(item => counts[item] === targetCount);
}

console.log("出现3次的元素:", filterByFrequency(numberArray, 3));
console.log("出现1次的元素:", filterByFrequency(numberArray, 1));

console.log("\n=== 总结 ===");
console.log(`
数组频次统计方法选择建议：

📋 方法分类：
1. 基础循环: for、while、forEach - 易理解，性能好
2. 函数式: reduce、filter - 代码简洁
3. 数据结构: Map、Set - 功能强大
4. 高级技巧: 递归、生成器、类封装 - 特殊场景

🎯 使用建议：
- 简单场景: reduce方法最简洁
- 性能要求: for循环或forEach
- 复杂统计: Map数据结构
- 对象数组: 自定义key函数
- 大数据: 避免filter方法(O(n²)复杂度)

⚠️ 注意事项：
- 混合类型数组需要特殊处理
- 对象数组建议使用JSON.stringify或自定义key
- filter方法性能较差，适合小数组
- Map数据结构能正确处理NaN和对象
- 考虑内存使用，大数组建议流式处理

🚀 性能排序：
for循环 ≈ forEach ≈ Map > reduce > filter
`);

// 推荐的通用方法
console.log("\n=== 推荐的通用方法 ===");
function countFrequency(arr, options = {}) {
    const { 
        keyFunc = null,           // 自定义key函数
        useMap = false,          // 是否使用Map
        sortResult = false       // 是否按频次排序
    } = options;
    
    let counts;
    
    if (useMap) {
        const map = new Map();
        arr.forEach(item => {
            const key = keyFunc ? keyFunc(item) : item;
            map.set(key, (map.get(key) || 0) + 1);
        });
        counts = Object.fromEntries(map);
    } else {
        counts = arr.reduce((acc, item) => {
            const key = keyFunc ? keyFunc(item) : item;
            acc[key] = (acc[key] || 0) + 1;
            return acc;
        }, {});
    }
    
    if (sortResult) {
        return Object.entries(counts)
            .sort((a, b) => b[1] - a[1])
            .reduce((acc, [key, value]) => {
                acc[key] = value;
                return acc;
            }, {});
    }
    
    return counts;
}

console.log("通用方法示例:");
console.log("基础统计:", countFrequency(numberArray));
console.log("排序结果:", countFrequency(numberArray, {sortResult: true}));
console.log("对象按id:", countFrequency(complexArray, {keyFunc: obj => obj.id})); 